#include "common.h"
#include "arrays.h"
#include "commands.h"


#define MAX_TOKENS (MAX_LEN / 2 + 1)


/****************************************************************************
** FUNCTION PROTOTYPES
****************************************************************************/
static success_t parse_args(int argc, const char ** argv);
static int tokenize(char * buf, char ** tokens, int max_tokens);
success_t run_script(void);


/****************************************************************************
** GLOBAL VARIABLES
****************************************************************************/
/* input and output streams, used by this program */
FILE * instream;
FILE * outstream;

/* the "database" arrays */
arr_t movies_arr;
arr_t games_arr;
arr_t playlists_arr;


/****************************************************************************
** FUNCTION IMPLEMENTATION
****************************************************************************/
int main(int argc, const char ** argv)
{
	/* init */
	instream = stdin;
	outstream = stdout;
	
	arr_init_movies(&movies_arr);
	arr_init_games(&games_arr);
	arr_init_playlists(&playlists_arr);
	
	/* process arguments and script file */
	if (parse_args(argc - 1, argv + 1))
	{
		run_script();
	}
	
	/* clean up */
	arr_fini(&movies_arr);
	arr_fini(&games_arr);
	arr_fini(&playlists_arr);
	
	if (instream != stdin && instream != NULL)
		if (fclose(instream) != 0)
			mtm_error(err_CloseFailed);
	if (outstream != stdout && outstream != NULL)
		if (fclose(outstream) != 0)
			mtm_error(err_CloseFailed);
	
	/* according to the exercise, always return 0 for the automaic tester */
	return 0;
}


/*---------------------------------------------------------------------------
parse_args: processes the command line arguments ("-i" and "-o"). it may
open files for reading (instream) or writing (outstream), according to the
command line. if 
 
params:
 * argc - the number of arguments (not including the program name)
 * argv - array of strings of the arguments (not including the program name)

retval: TRUE if successful, FALSE if command line arguments are wrong, in
which case the program should quit immediately

notes:
instream and outstream are global, initialized to stdin and stdout 
respectively, and will be changed only if -i or -o are specified in the 
command line.
---------------------------------------------------------------------------*/
static success_t parse_args(int argc, const char ** argv)
{
	int i;
	
	for (i = 0; i < argc; i++)
	{
		if (strcmp(argv[i], "-i") == 0)
		{
			/* already given -i ? */
			ASSERT_FATAL(instream == stdin, err_WrongArguments);
			i++;
			instream = fopen(argv[i], "r");
			/* failed to open file ? */
			ASSERT_FATAL(instream != NULL, err_OpenFailed); 
		}
		else if (strcmp(argv[i], "-o") == 0)
		{
			/* already given -o ? */
			ASSERT_FATAL(outstream == stdout, err_WrongArguments);
			i++;
			outstream = fopen(argv[i], "w");
			/* failed to open file ? */
			ASSERT_FATAL(outstream != NULL, err_OpenFailed);
		}
		else 
		{
			/* invalid switch */
			mtm_error(err_WrongArguments);
			return FALSE;
		}
	}
	
	return TRUE;
}


/*---------------------------------------------------------------------------
tokenize: tokenizes (splits) a string buffer into tokens (words). tokens
are delimited by space, tab, CR or LF.
 
params:
 * buf - the buffer to tokenize
 * tokens - OUT PARAM: the array that will store the tokens (array of strings)
 * max_tokens - the maximal number of tokens in the array

retval: the actual number of tokens found, up to max_tokens

notes:
the input buffer will be changed (\0 will be embedded after words)
---------------------------------------------------------------------------*/
static int tokenize(char * buf, char ** tokens, int max_tokens)
{
	int i;
	int j = 0;
	bool_t whitespace = TRUE;
	
	for (i = 0; buf[i] != '\0'; i++)
	{
		if (buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n' || buf[i] == '\r')
		{
			buf[i] = '\0';
			whitespace = TRUE;
		}
		else if (whitespace)
		{
			if (j > max_tokens)
				break;
			tokens[j] = &buf[i];
			j++;
			whitespace = FALSE;
		}
	}
	
	return j;
}


/*---------------------------------------------------------------------------
run_script: executes the script file, line by line, ignoring empty and 
comment lines

params: none

retval: TRUE if successful, FALSE otherwise

notes: reads data from instream (which is a global variable)
---------------------------------------------------------------------------*/
success_t run_script(void)
{
	char linebuf[MAX_LEN + 1];
	char * tokens[MAX_TOKENS];
	int cnt;
	
	while (!feof(instream))
	{
		if (fgets(linebuf, MAX_LEN, instream) == NULL)
		{
			/* UNREPORTABLE ERROR: error reading stream */
			return FALSE;
		}
		
		/* tokenize line, skip if empty or comment */
		cnt = tokenize(linebuf, (char**)tokens, MAX_TOKENS);
		if (cnt == 0)
			continue;
		if (tokens[0][0] == ';')
			continue;
		if (!cmd_dispatch(tokens[0], (const char**)(&tokens[1])))
			return FALSE;
	}
	
	return TRUE;
}








